package com.yhh.college_information_platform.interceptor;

import com.yhh.college_information_platform.annotation.PublicAccess;
import com.yhh.college_information_platform.annotation.RequireAuth;
import com.yhh.college_information_platform.annotation.RequireRole;
import com.yhh.college_information_platform.common.ResultCode;
import com.yhh.college_information_platform.constant.RoleConstant;
import com.yhh.college_information_platform.exception.BusinessException;
import com.yhh.college_information_platform.utils.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.Arrays;

/**
 * JWT认证拦截器（支持注解式权限控制）
 *
 * @author yhh
 * @date 2025-10-05
 * @update 2025-10-30 添加游客模式和角色验证
 */
@Slf4j
@Component
public class AuthInterceptor implements HandlerInterceptor {

    @Autowired
    private JwtUtil jwtUtil;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // 处理跨域预检请求
        if ("OPTIONS".equals(request.getMethod())) {
            return true;
        }

        // 如果不是方法处理器，直接放行
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        Class<?> clazz = handlerMethod.getBeanType();

        // 1. 检查是否有@PublicAccess注解（方法级别或类级别）
        PublicAccess publicAccess = method.getAnnotation(PublicAccess.class);
        if (publicAccess == null) {
            publicAccess = clazz.getAnnotation(PublicAccess.class);
        }

        // 如果有@PublicAccess注解，允许游客访问
        if (publicAccess != null) {
            log.info("=== 公开访问接口: URI={} ===", request.getRequestURI());
            
            // 尝试解析Token（如果有），但不强制要求
            String token = getTokenFromRequest(request);
            if (token != null && jwtUtil.validateToken(token)) {
                setUserInfo(request, token);
            } else {
                // 游客模式，设置默认属性
                request.setAttribute("userId", null);
                request.setAttribute("studentId", null);
                request.setAttribute("role", RoleConstant.GUEST);
            }
            return true;
        }

        // 2. 检查是否需要登录认证
        RequireAuth requireAuth = method.getAnnotation(RequireAuth.class);
        if (requireAuth == null) {
            requireAuth = clazz.getAnnotation(RequireAuth.class);
        }

        // 默认需要登录（如果既没有@PublicAccess也没有@RequireAuth，则需要登录）
        boolean needAuth = requireAuth == null || requireAuth.required();

        // 获取并验证Token
        String token = getTokenFromRequest(request);
        if (token == null || token.isEmpty()) {
            if (needAuth) {
                throw new BusinessException(ResultCode.UNAUTHORIZED, "请先登录");
            }
            return true;
        }

        // 验证Token有效性
        if (!jwtUtil.validateToken(token)) {
            if (jwtUtil.isTokenExpired(token)) {
                throw new BusinessException(ResultCode.TOKEN_EXPIRED, "登录已过期，请重新登录");
            }
            throw new BusinessException(ResultCode.TOKEN_INVALID, "登录信息无效，请重新登录");
        }

        // 设置用户信息
        setUserInfo(request, token);

        // 3. 检查角色权限
        RequireRole requireRole = method.getAnnotation(RequireRole.class);
        if (requireRole == null) {
            requireRole = clazz.getAnnotation(RequireRole.class);
        }

        if (requireRole != null) {
            String userRole = (String) request.getAttribute("role");
            String[] allowedRoles = requireRole.value();
            
            boolean hasPermission = Arrays.asList(allowedRoles).contains(userRole);
            if (!hasPermission) {
                log.warn("=== 权限不足: URI={}, 用户角色={}, 需要角色={} ===", 
                        request.getRequestURI(), userRole, Arrays.toString(allowedRoles));
                throw new BusinessException(ResultCode.FORBIDDEN, "权限不足，无法访问该资源");
            }
            
            log.info("=== 角色验证通过: URI={}, 用户角色={} ===", request.getRequestURI(), userRole);
        }

        return true;
    }

    /**
     * 从请求中获取Token
     */
    private String getTokenFromRequest(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        if (token != null && token.startsWith("Bearer ")) {
            return token.substring(7);
        }
        return token;
    }

    /**
     * 设置用户信息到请求属性
     */
    private void setUserInfo(HttpServletRequest request, String token) {
        Long userId = jwtUtil.getUserIdFromToken(token);
        String studentId = jwtUtil.getStudentIdFromToken(token);
        String role = jwtUtil.getRoleFromToken(token);

        log.info("=== 用户认证成功: URI={}, userId={}, studentId={}, role={} ===", 
                request.getRequestURI(), userId, studentId, role);

        request.setAttribute("userId", userId);
        request.setAttribute("studentId", studentId);
        request.setAttribute("role", role);
    }
}
